/*
	WorkStealingContainer implements an array of M&S queues with the following properties:
	1. allocates M&S queue per consumer
	2. consumer retrieves tasks from it own queue.
	   If the queue is empty, the consumer traverses in random order queues of other consumers and tries to retrieve a task from them.
	   If all queues of all consumers are empty - returns null
	3. Producer inserts a task into a randomly chosen queue.
*/
#ifndef WORKSTEALINGCONTAINER_H_
#define WORKSTEALINGCONTAINER_H_
#include "TaskContainer.h"
#include "MSQueue.hpp"
#include <time.h>
#include <iostream>
using namespace std;

class WorkStealingContainer : public TaskContainer{
	/* array of M&S queues */
	MSQueue<Task*>** queues; 
	
	/* a thread-local variable - per consumer thread. Indicates the consumer's queue */
	static __thread int queueNum;
	
	/* number of consumers working on the container */
	int consumerCount;
	
	/* maximal number of consumers to work on the container */
	int maxConsumerNum;
	
	/* number of initialized M&S queues in the container */
	int containerSize;
	
	void registerConsumer();
public:
	/******** debug info ********/
	/* distribution of inserted tasks between queues */
	//int* taskCounters; 
	
	/* distribution of retrievals between queues for each consumer */
	//int** consumerDistribution;  
	
	//int getDebugInfo(){return queueNum;}
	/****************************/
	
	WorkStealingContainer(int maxConsumerNum);
	virtual ~WorkStealingContainer();
	
	/* allocate and initialize a queue for the consumer */
	void registerConsumer(int tid){registerConsumer();}
	
	/* initialize seed for random insertions */
	void registerProducer(int tid);
	
	
	void put(Task* task, Statistics* stat);
	Task* get(Statistics* stat);
	
	void init(){}	
	//void setConsumersNum(int consumersNum){} 
};
#endif  /* WORKSTEALINGCONTAINER_H_ */